
/*============================================================================
 PROJECT: Halalgems
 FILE:    DataCenter.m
 AUTHOR:  Nguyen Minh Khoai
 =============================================================================*/

/*============================================================================
 IMPORT
 =============================================================================*/

#import "DataCenter.h"
#import "GoogleGeocodingResult.h"
#import "GooglePlaceDetailItem.h"
#import "GooglePrediction.h"
#import "DirectionInfo.h"
#import "LeftMenu.h"
#import "AuthorModal.h"
/*============================================================================
 MACRO
 =============================================================================*/

#define kGoogleMapAPIHost               @"https://maps.googleapis.com/"
#define kGoogleAPIPlaceSearchPath       @"maps/api/place/autocomplete/json"
#define kGoogleAPIPlaceDetailPath       @"maps/api/place/details/json"
#define kGoogleAPIKey                   @"AIzaSyDviEQ_rkCCFJzwyrbtFREw39Cwu-oAIcg"
#define kGetRoutesBetweenTwoPoints      @"http://maps.googleapis.com/maps/api/directions/json?origin=%@&destination=%@&mode=%@&sensor=false&language=%@"

/* define cached key */
#define kCookieKey                      @"kCookieKey"
typedef NS_ENUM(NSInteger, ErrorType) {
    
    kErrorTypeNone = 0,
    
    /* Accesstoken*/
    kErrorTypeAccessTokenExpired = 600,
    kErrorTypeAccessDenied = 902,
    
    /* Message from API*/
    kErrorTypeLoginWrong = 602,
    
    kErrorTypeUnknown
    
};
/*============================================================================
 PRIVATE INTERFACE
 =============================================================================*/

/*----------------------------------------------------------------------------
 Interface:   DataCenter
 -----------------------------------------------------------------------------*/
@interface DataCenter() {
    
}


@property (nonatomic, strong) LocationService *service;

@end

@implementation DataCenter
#pragma mark - Method Helper
- (ErrorType)checkErrorFromResponse:(id)response {
    ErrorType errorType = kErrorTypeNone;
    
    NSError *error = nil;
    if (![JSONHelper isValidJSONFromDictionary:response error:&error]) {
        errorType = error.code;
        
    }
    else {
        errorType = kErrorTypeNone;
    }
    
    return errorType;
}
#pragma mark - Alo Truyen

-(void)getBookFromLeftMenuWithSpecID:(NSString *)specID
                            andBlock:(void (^)(id, id))block{
    @autoreleasepool {
        [self callGETServiceWithURL:Str4Fmt(@"/v1/left_menu_detail.json?spec_id=%@", specID)
                             params:nil
                       successBlock:^(id result) {
                           ErrorType errorType = [self checkErrorFromResponse:result];
                           if (errorType == kErrorTypeNone) {
                               NSMutableArray *leftMenu = [NSMutableArray array];
                               for (NSDictionary *objs in result[@"data"][@"list_entity"]) {
                                   AloTruyenModal *obj = [[AloTruyenModal alloc]initHomeItemWithSpecIDFromLeftMenu:objs];
                                   [leftMenu addObject:obj];
                               }
                               block(leftMenu,nil);
                           }else if (errorType == kErrorTypeAccessTokenExpired){
                               NotifPost(kPushErrorAccessToken);
                           }else{
                               block(nil,result[kErrorMessageKey]);
                           }

                       }
                         errorBlock:^(id error) {
                             block(nil,error);
                         }];
    }
}

-(void)getAuthorListWithBlock:(void (^)(id, id))block{
    @autoreleasepool {
        [self callGETServiceWithURL:@"/v1/authors.json?page_index=1&page_size=20&order_type=1"
                             params:nil
                       successBlock:^(id result) {
                           ErrorType errorType = [self checkErrorFromResponse:result];
                           if (errorType == kErrorTypeNone) {
                               NSMutableArray *leftMenu = [NSMutableArray array];
                               for (NSDictionary *objs in result[@"data"]) {
                                   AuthorModal *obj = [[AuthorModal alloc]initAuthorWithParams:objs];
                                   [leftMenu addObject:obj];
                               }
                               block(leftMenu,nil);
                           }else if (errorType == kErrorTypeAccessTokenExpired){
                               NotifPost(kPushErrorAccessToken);
                           }else{
                               block(nil,result[kErrorMessageKey]);
                           }

                       }
                         errorBlock:^(id error) {
                             block(nil,error);
                         }];
    }
}

-(void)getMenuFromHomeWithBlock:(void (^)(id, id))block{
    @autoreleasepool {
        [self callGETServiceWithURL:@"/v1/home_screen.json"
                             params:nil
                       successBlock:^(id result) {
                           ErrorType errorType = [self checkErrorFromResponse:result];
                           if (errorType == kErrorTypeNone) {
                               NSMutableArray *leftMenu = [NSMutableArray array];
                               for (NSDictionary *objs in result[@"data"][@"home_items"]) {
                                   AloTruyenModal *obj = [[AloTruyenModal alloc]initHomeItemWithDictionary:objs];
                                   [leftMenu addObject:obj];
                               }
                               block(leftMenu,nil);
                           }else if (errorType == kErrorTypeAccessTokenExpired){
                               NotifPost(kPushErrorAccessToken);
                           }else{
                               block(nil,result[kErrorMessageKey]);
                           }

                       }
                         errorBlock:^(id error) {
                             
                         }];
    }
}

-(void)getMenuFromLeftMenu:(NSString *)url
                  andBlock:(void (^)(id, id))block{
    @autoreleasepool {
        [self callGETServiceWithURL:url
                             params:nil
                       successBlock:^(id result) {
                           ErrorType errorType = [self checkErrorFromResponse:result];
                           if (errorType == kErrorTypeNone) {
                               NSMutableArray *leftMenu = [NSMutableArray array];
                               for (NSDictionary *objs in result[@"data"]) {
                                   LeftMenu *obj = [[LeftMenu alloc]initLeftMenuWithDictionary:objs];
                                   [leftMenu addObject:obj];
                               }
                               block(leftMenu,nil);
                           }else if (errorType == kErrorTypeAccessTokenExpired){
                               NotifPost(kPushErrorAccessToken);
                           }else{
                               block(nil,result[kErrorMessageKey]);
                           }
                           
                       }
                         errorBlock:^(id error) {
                             block(nil,error);
                         }];

    }
}

-(void)getBookWithURL:(NSString *)url
             andBlock:(void (^)(id, id))block{
    [self callGETServiceWithURL:url
                         params:nil
                   successBlock:^(id result) {
                       ErrorType errorType = [self checkErrorFromResponse:result];
                       if (errorType == kErrorTypeNone) {
                           NSMutableArray *array = [NSMutableArray array];
                           for (NSDictionary *params in result[@"data"]) {
                               AloTruyenModal *modal = [[AloTruyenModal alloc]initWithDictionary:params];
                               [array addObject:modal];
                           }
                           block(array,nil);
                       }else if (errorType == kErrorTypeAccessTokenExpired){
                           NotifPost(kPushErrorAccessToken);
                       }else{
                           block(nil,result[kErrorMessageKey]);
                       }
                   }
                     errorBlock:^(id error) {
                         block(nil,error);
                         NSLog(@"Error :%@",error);
                     }];
}
//@synthesize activeUser;

- (id)init {
    self = [super init];
    if (self) {
        /* load previous user information */
//        self.activeUser = [appDelegate.dataHelper onlineUser];
        [[AFNetworkActivityIndicatorManager sharedManager] setEnabled:YES];
    }
    return self;
}

#pragma mark - Support WSDL Requests


/*----------------------------------------------------------------------------
 Method:      updateCookies
 Description: Update cookies for http request
 ----------------------------------------------------------------------------*/
- (void)updateCookies {
    NSArray *cookies = [FileHelper restoreArrayForKey:kCookieKey];
    [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:cookies forURL:[BaseNetwork service].networkEngine.baseURL mainDocumentURL:nil];
}

/*----------------------------------------------------------------------------
 Method:      callServiceWithBody
 Description: call a service with body and headers
 ----------------------------------------------------------------------------*/
- (void)callServiceWithBody:(NSString *)body
                httpHeaders:(NSMutableDictionary *)headers
                 httpMethod:(NSString *)method
               successBlock:(void (^)(id))successBlock
                 errorBlock:(void (^)(id))errorBlock {
    
    /* set default headers */
    BaseNetwork *baseService = [BaseNetwork service];
    baseService.enableDebugLog = NO;
    
    /* call service with parameter */
    [baseService requestWithHttpBody:body
                        headerFields:headers
                        successBlock:^(id data) {
                            successBlock(data);
                        }
                          errorBlock:^(NSString *error) {
                              /* handle error */
                              NSString *errorMsg = error;
                              if (errorMsg) {
                                  errorMsg = kServiceNotAvailableMessage;
                              }
                              errorBlock(errorMsg);
                          }
                          httpMethod:method];
}

/*----------------------------------------------------------------------------
 Method:      callPOSTServiceWithBody
 Description: call a post request with body, headers
 ----------------------------------------------------------------------------*/
- (void)callPOSTServiceWithBody:(NSString *)body
                    httpHeaders:(NSMutableDictionary *)headers
                   successBlock:(void (^)(id))successBlock
                     errorBlock:(void (^)(id))errorBlock {
    [self callServiceWithBody:body
                  httpHeaders:headers
                   httpMethod:@"POST"
                 successBlock:successBlock
                   errorBlock:errorBlock];
}

#pragma mark - Support Normal Request
/*----------------------------------------------------------------------------
 Method:      callServiceWithURL
 Description: call a service with url, parameters and method name
 ----------------------------------------------------------------------------*/
- (void)callServiceWithURL:(NSString *)url
                    params:(NSMutableDictionary *)params
                httpMethod:(NSString *)method
              successBlock:(void (^)(id))successBlock
                errorBlock:(void (^)(id))errorBlock {
    
    /* set default headers */
    BaseNetwork *baseService = [BaseNetwork service];
    baseService.enableDebugLog = NO;
    
    /* call service with parameter */
    [baseService requestWithURL:url
                         params:params
                   successBlock:^(NSDictionary *data) {
                       successBlock(data);
                   }
                     errorBlock:^(NSString *error) {
                         errorBlock(error);
                     }
                     httpMethod:method];
}

/*----------------------------------------------------------------------------
 Method:      callGETServiceWithURL
 Description: call a get request with url and parameters
 ----------------------------------------------------------------------------*/
- (void)callGETServiceWithURL:(NSString *)url
                       params:(NSMutableDictionary *)params
                 successBlock:(void (^)(id))successBlock
                   errorBlock:(void (^)(id))errorBlock {
    
    [self callServiceWithURL:url
                      params:params
                  httpMethod:@"GET"
                successBlock:^(id dataJson) {
                    successBlock(dataJson);
                }
                  errorBlock:^(id dataJson) {
                      errorBlock(dataJson);
                  }];
}

/*----------------------------------------------------------------------------
 Method:      callPOSTServiceWithURL
 Description: call a get request with url and parameters
 ----------------------------------------------------------------------------*/
- (void)callPUTServiceWithURL:(NSString *)url
                       params:(NSMutableDictionary *)params
                 successBlock:(void (^)(id))successBlock
                   errorBlock:(void (^)(id))errorBlock {
    [self callServiceWithURL:url
                      params:params
                  httpMethod:@"PUT"
                successBlock:successBlock
                  errorBlock:errorBlock];
}

/*----------------------------------------------------------------------------
 Method:      callPOSTServiceWithURL
 Description: call a post request with url and parameters
 ----------------------------------------------------------------------------*/
- (void)callPOSTServiceWithURL:(NSString *)url
                        params:(NSMutableDictionary *)params
                  successBlock:(void (^)(id))successBlock
                    errorBlock:(void (^)(id))errorBlock {
    [self callServiceWithURL:url
                      params:params
                  httpMethod:@"POST"
                successBlock:successBlock
                  errorBlock:errorBlock];
}

/*----------------------------------------------------------------------------
 Method:      callDELETEServiceWithURL
 Description: call a delete request with url and parameters
 ----------------------------------------------------------------------------*/
- (void)callDELETEServiceWithURL:(NSString *)url
                          params:(NSMutableDictionary *)params
                    successBlock:(void (^)(id))successBlock
                      errorBlock:(void (^)(id))errorBlock {
    [self callServiceWithURL:url
                      params:params
                  httpMethod:@"DELETE"
                successBlock:successBlock
                  errorBlock:errorBlock];
}

#pragma mark - Support form requests
/*----------------------------------------------------------------------------
 Method:      callFormRequestServiceWithPath
 Description: call a form request service with path, parameters and method name
 ----------------------------------------------------------------------------*/
- (void)callFormRequestServiceWithPath:(NSString *)path
                                params:(NSMutableDictionary *)params
                              filePath:(NSString *)filePath
                                  name:(NSString *)name
                         authenticated:(BOOL)status
                          successBlock:(void (^)(id))successBlock
                            errorBlock:(void (^)(id))errorBlock {
    if(!status) {
        /* set default headers */
        BaseNetwork *baseService = [BaseNetwork service];
        
        /* call service with parameter */
        [baseService formRequestWithURLPath:path
                                     params:params
                                   filePath:filePath
                                       name:name
                               successBlock:^(NSDictionary *data) {
                                   successBlock(data);
                               } errorBlock:^(NSString *error) {
                                   /* handle error */
                                   NSString *errorMsg = error;
                                   if(!error) {
                                       errorMsg = kServiceNotAvailableMessage;
                                   }
                                   errorBlock(errorMsg);
                               }];
    } else {
        errorBlock(kAuthenticationFailedMessage);
    }
}


/*----------------------------------------------------------------------------
 Method:      callFormRequestServiceWithPath
 Description: call a form request service with path, parameters and method name
 ----------------------------------------------------------------------------*/
- (void)callFormRequestServiceWithPath:(NSString *)path
                                params:(NSMutableDictionary *)params
                                 image:image
                         authenticated:(BOOL)status
                          successBlock:(void (^)(id))successBlock
                            errorBlock:(void (^)(id))errorBlock
                         progressBlock:(void (^)(long long totalBytesWritten, long long totalBytesExpectedToWrite))progressBlock{
    if(!status) {
        /* call service with parameter */
        BaseNetwork *baseNetwork = [BaseNetwork service];
        baseNetwork.enableDebugLog = NO;
        [baseNetwork formRequestWithURLPath:path
                                     params:params
                                      image:image
                               successBlock:^(NSDictionary *data) {
                                   successBlock(data);
                               } errorBlock:^(NSString *error) {
                                   /* handle error */
                                   NSString *errorMsg = error;
                                   if(!error) {
                                       errorMsg = kServiceNotAvailableMessage;
                                   }
                                   errorBlock(errorMsg);
                               } progressBlock:^(long long totalBytesWritten, long long totalBytesExpectedToWrite) {
                                   progressBlock(totalBytesWritten, totalBytesExpectedToWrite);
                               }];
    } else {
        errorBlock(kAuthenticationFailedMessage);
    }
}

/*----------------------------------------------------------------------------
 Method:      callFormRequestPOSTServiceWithPath
 Description: call a form request with path and parameters
 ----------------------------------------------------------------------------*/
- (void)callFormRequestPOSTServiceWithPath:(NSString *)path
                                    params:(NSMutableDictionary *)params
                              successBlock:(void (^)(id))successBlock
                                errorBlock:(void (^)(id))errorBlock {
    [self callFormRequestServiceWithPath:path
                                  params:params
                                filePath:nil
                                    name:nil
                           authenticated:YES
                            successBlock:successBlock
                              errorBlock:errorBlock];
}

/*----------------------------------------------------------------------------
 Method:      callFormRequestPOSTServiceWithPath
 Description: call a form request with path and parameters
 ----------------------------------------------------------------------------*/
- (void)callFormRequestPOSTServiceWithPath:(NSString *)path
                                    params:(NSMutableDictionary *)params
                                  filePath:(NSString *)filePath
                                      name:(NSString *)name
                              successBlock:(void (^)(id))successBlock
                                errorBlock:(void (^)(id))errorBlock {
    [self callFormRequestServiceWithPath:path
                                  params:params
                                filePath:filePath
                                    name:name
                           authenticated:NO
                            successBlock:successBlock
                              errorBlock:errorBlock];
}

#pragma mark - Google Service APIs

- (void)getCurrentLocationUsingBlock:(void (^)(id data, id error))block {
    
    if (!_service) {
        LocationService *service = [[LocationService alloc] init];
        self.service = service;
    }
    
    [_service getUpdateLocationWithCallback:^(CLLocation *location, NSError *error) {
        
        if(error) {
            block(nil, [error localizedFailureReason]);
            return;
        }
        
        GooglePlaceDetailItem *detailLocation = [[GooglePlaceDetailItem alloc] init];
        detailLocation.latitude = [NSString stringWithFormat:@"%f", location.coordinate.latitude];
        detailLocation.longtitude = [NSString stringWithFormat:@"%f", location.coordinate.longitude];
        block(detailLocation, nil);
        
    }];
}

- (void)getHintListFromGoogle:(NSString *)keyword usingBlock:(void (^)(id data, id error))block {
    NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
    
    [params setObject:keyword forKey:@"input"];
    [params setObject:@"true" forKey:@"sensor"];
    [params setObject:kGoogleAPIKey forKey:@"key"];
    
    BaseNetwork *apiService = [[BaseNetwork alloc] initWithBaseURL:kGoogleMapAPIHost];
    [apiService requestWithURL:kGoogleAPIPlaceSearchPath params:params successBlock:^(NSDictionary *data) {
         NSMutableArray *googleHintList = [[NSMutableArray alloc] init];
         NSMutableArray *googlePredictions = [data objectForKey:@"predictions"];

        for (NSDictionary *prediction in googlePredictions){
             GooglePrediction *googlePredic = [[GooglePrediction alloc] init];
             googlePredic.description = [prediction objectForKey:@"description"];
             googlePredic.reference = [prediction objectForKey:@"reference"];
             [googleHintList addObject:googlePredic];
         }
         block(googleHintList, nil);
     } errorBlock:^(NSString *error) {
         block(nil, error);
     } httpMethod:@"GET"];
}

- (void) getPlaceDetailFromGoogle:(GooglePrediction *)prediction usingBlock:(void (^)(id data, id error))block {
    NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
    
    [params setObject:prediction.reference forKey:@"reference"];
    [params setObject:@"true" forKey:@"sensor"];
    [params setObject:kGoogleAPIKey forKey:@"key"];
    
    BaseNetwork *apiService = [[BaseNetwork alloc] initWithBaseURL:kGoogleMapAPIHost];
    [apiService requestWithURL:kGoogleAPIPlaceDetailPath params:params successBlock:^(NSDictionary *data) {
         NSDictionary *detail = [data objectForKey:@"result"];
         GooglePlaceDetailItem *detailItem = [[GooglePlaceDetailItem alloc] init];
         detailItem.name = [detail objectForKey:@"name"];
         detailItem.longtitude = [[[detail objectForKey:@"geometry"] objectForKey:@"location"] objectForKey:@"lng"];
         detailItem.latitude = [[[detail objectForKey:@"geometry"] objectForKey:@"location"] objectForKey:@"lat"];
         detailItem.iconUrl = [detail objectForKey:@"icon"];
         
         block(detailItem, nil);
     } errorBlock:^(NSString *error) {
         block(nil, error);
     } httpMethod:@"GET"];
}

/* get directions */
- (void)getRoutesBetweenA:(CLLocation *)locationA
                     andB:(CLLocation *)locationB
                   inMode:(NSString *)mode
               usingBlock:(void (^)(id data, id error))block {
    
    if (!_service) {
        self.service = [[LocationService alloc] init];
    }
    
    [_service getUpdateLocationWithCallback:^(CLLocation *location, NSError *error) {
        if(error) {
            block(nil, [error localizedFailureReason]);
            return;
        }
        NSString *origin = [NSString stringWithFormat:@"%f,%f", location.coordinate.latitude, location.coordinate.longitude];
        NSString *destination = [NSString stringWithFormat:@"%f,%f", locationB.coordinate.latitude, locationB.coordinate.longitude];
        
        NSString *urlRequestString = [NSString stringWithFormat:kGetRoutesBetweenTwoPoints, origin, destination, mode, [[NSLocale preferredLanguages] objectAtIndex:0]];
        
        [[BaseNetwork service] requestWithURL:urlRequestString
                                       params:nil
                                 successBlock:^(NSDictionary *data) {
                                     NSDictionary *responseJSON = data;
                                     DirectionInfo *info = [[DirectionInfo alloc] init];
                                     
                                     /* get routes */
                                     NSArray *routes = [responseJSON objectForKey:@"routes"];
                                     
                                     if ([routes count] > 0) {
                                         NSDictionary *routeDict = [routes objectAtIndex:0];
                                         [info setupWithDictionary:routeDict];
                                     };
                                     block(info, nil);
                                 } errorBlock:^(NSString *error) {
                                     block(nil, error);
                                 } httpMethod:@"GET"];
        
    }];
}

@end